
#include "sta.h"

static xSemaphoreHandle lock_sta;
static char bssid_str[]="BSSID: ";
static char ssid_str[]="SSID: ";
static char channel_str[]="Channel: ";
static char rssi_str[]="Single Strength: ";
static char authmode_str[]="Authenticate Mode: ";
static char hidden_str[]=  "Hidden: ";
static char apblk_separator[] = "***********************************";
static char no_str[] = "No.";
static char no_ap_found_str[] = "No Ap Found!!!";
static char disconnected_str[] = "Disconnect From SSID: ";
static char reason_str[] = "Reason: ";
static char unknown_str[] = "Unknown: ";
static char auth_leave_str[] = "Auth Leave!!!";
static char not_auth_str[] = "Not Auth!!!";
static char assoc_leave_str[] = "Assoc Leave!!!";


static int8 lap_pos;
static int8 detail_pos;
static int8 jap_pos;
static int8 qap_pos;

void initStaCmd()
{
	vSemaphoreCreateBinary(lock_sta);
	xSemaphoreTake(lock_sta, portMAX_DELAY);
}
xSemaphoreHandle lock;

void  cmdTask(void* para)
{
	for(;;)
	{
		xSemaphoreTake(lock, portMAX_DELAY);
		
		initCmdLine(); 
		parseCmdLine(); 
		doCmd();
	}
	vTaskDelete(NULL);
}

void uart0_rx_intr_handler_new(void *para)
{
	uint8 RcvChar;
    UARTPort uart_no = UART0;
    uint8 fifo_len = 0;
    uint8 buf_idx = 0;
	uint8 cmdline_end=0;
	static portBASE_TYPE xHigherPriorityTaskWoken;
	

    uint32 uart_intr_status = GET_UART_INT_ST(uart_no);
	xHigherPriorityTaskWoken = pdFALSE;
	if (BIT_TEST(uart_intr_status,UART_RXFIFO_FULL_INT_ST))
    {
        fifo_len = RX_FIFO_LEN(uart_no);
        buf_idx = 0;
        while (buf_idx < fifo_len)
		{
			RcvChar = READ_UART_BYTE(uart_no);
            buf_idx++;
        }
    } 
	if (BIT_TEST(uart_intr_status,UART_RXFIFO_TOUT_INT_ST)) 
	{
        fifo_len = RX_FIFO_LEN(uart_no);
        buf_idx = 0;
        while (buf_idx < fifo_len)
		{
			RcvChar = READ_UART_BYTE(uart_no);
			if(cmdline_end == 0)
				cmdline_end = copyCmdCharToBuf(RcvChar);
            buf_idx++;
        }
		if(cmdline_end == 1)
		{
			xSemaphoreGiveFromISR(lock, &xHigherPriorityTaskWoken);
			if(xHigherPriorityTaskWoken == pdTRUE)
			{
				//vTaskSwitchContext();
			}
		}
			
    } 
	CLC_RXFIFO_INT_ST(uart_no);
}
void staCmd()
{
	count_t1 i,j;
	ParaStr para;
	ParaStr ssid_para;
	ParaStr passwd_para;

	lap_pos = -1;
	detail_pos = -1;
	jap_pos = -1;
	qap_pos = -1;
	wifi_set_event_handler_cb(sta_wifi_event_handler);

	for(i=0;i<PARA_COUNT;i++)
	{
		for(j=0;j<SUBOPT_COUNT(i);j++) 
		{
			getSubOptStr(i,j,&para);
			if(myStrCmp(para.addr,STA_OPT_LAP,para.len))
			{
				lap_pos = i;
				getSubOptStr(i,j+1,&para);
				if(myStrCmp(para.addr,STA_OPT_DETAIL,para.len))
					detail_pos = i;
				goto Get_Para;
			}
			else if(myStrCmp(para.addr,STA_OPT_JAP,para.len))
			{
				getSubParaStr(i, 0, &ssid_para);
				getSubParaStr(i, 1, &passwd_para);
				if(ssid_para.len > 0 && passwd_para.len >0)
					jap_pos = i;
				goto Get_Para;
			}
			else if(myStrCmp(para.addr,STA_OPT_QAP,para.len))
			{
				qap_pos = i;
				goto Get_Para;
			}
			
		}
	}
Get_Para:
	if(lap_pos >= 0)
	{
		if(detail_pos < 0)
			scan_ap(scan_done_op_simple);
		else
			scan_ap(scan_done_op_detail);
	}
	else if(jap_pos >= 0)
		joinAP(ssid_para.addr,ssid_para.len,passwd_para.addr,passwd_para.len);
	else if(qap_pos >= 0)
	{
		wifi_station_disconnect();
		xSemaphoreTake(lock_sta, 1000 / portTICK_RATE_MS); //1000ms
	}
		
	endCmd();
	wifi_set_event_handler_cb(NULL);
}

static void scan_ap(scan_done_cb_t cb)
{
	printf("Scaning.....");
	wifi_station_scan(NULL,cb);
	xSemaphoreTake(lock_sta, portMAX_DELAY);
	printf("Scan Done!!");
}
static void scan_done_op_simple(void* arg,STATUS status)
{
	count_t1 count = 0;
	if(status!=OK)
	{
		printf("Scan Falied!!!");
		return;
	}
	struct bss_info* ap_link = (struct bss_info*)arg;
	printf("%s\n",apblk_separator);
	while(ap_link!=NULL)
	{
		printf("%s%02d %s\n",no_str,++count,(char*)(ap_link->ssid));
		ap_link=ap_link->next.stqe_next;
	}
	printf("%s\n",apblk_separator);
	xSemaphoreGive(lock_sta);
}


static void scan_done_op_detail(void* arg,STATUS status)
{
	count_t1 count = 0;
	if(status!=OK)
	{
		printf("Scan Falied!!!");
		return;
	}
	struct bss_info* ap_link = (struct bss_info*)arg;
	while(ap_link!=NULL)
	{
		printf("%s\n",apblk_separator);
		printf("%s%02d\n",no_str,++count);
		printf("%s%X:%X:%X:%X:%X:%X\n",bssid_str,
			ap_link->bssid[0],ap_link->bssid[1],ap_link->bssid[2],
			ap_link->bssid[3],ap_link->bssid[4],ap_link->bssid[5]);
		
		printf("%s%s\n",ssid_str,(char*)(ap_link->ssid));
		printf("%s%d\n",channel_str,ap_link->channel);
		printf("%s%ddbm\n",rssi_str,ap_link->rssi);
		switch(ap_link->authmode)
		{
		case AUTH_OPEN:
			printf("%sOpen\n",authmode_str);
			break;
		case AUTH_WEP:
			printf("%sWEP\n",authmode_str);
			break;
		case AUTH_WPA2_PSK:
			printf("%sWPA2_PSK\n",authmode_str);
			break;
		case AUTH_WPA_PSK:
			printf("%sWPA_PSK\n",authmode_str);
			break;
		case AUTH_WPA_WPA2_PSK:
			printf("%sWPA_WPA2_PSK\n",authmode_str);
			break;
		default:
			printf("%sNULL\n",authmode_str);
			break;
		}
		if(ap_link->is_hidden)
			printf("%sYes\n",hidden_str);
		else
			printf("%sNo\n",hidden_str);
		ap_link=ap_link->next.stqe_next;
	}
	printf("%s\n",apblk_separator);
	xSemaphoreGive(lock_sta);
}

static void joinAP(int8* ssid,count_t1 ssid_len,int8* passwd,count_t1 passwd_len)
{
	if(ssid_len >= 32 || passwd_len >= 64)
		return;
	struct station_config ap;
	memcpy(ap.ssid, ssid, ssid_len);
	ap.ssid[ssid_len]=0;
	memcpy(ap.password, passwd, passwd_len);
	ap.password[passwd_len]=0;
	ap.bssid_set = 0;
	wifi_station_disconnect();
	wifi_station_set_config_current(&ap);
	wifi_station_connect();
	xSemaphoreTake(lock_sta, portMAX_DELAY);
}


static void sta_wifi_event_handler(System_Event_t *evt)
{
	switch (evt->event_id)
	{
	case EVENT_STAMODE_CONNECTED:
		xSemaphoreGive(lock_sta);
		break;
	case EVENT_STAMODE_DISCONNECTED:
	{
		printf("%s%s, %s",disconnected_str,
			evt->event_info.disconnected.ssid,
			reason_str);
		switch(evt->event_info.disconnected.reason)
		{
		case REASON_AUTH_LEAVE:
			printf("%s\n",auth_leave_str);
			break;
		case REASON_NOT_AUTHED:
			printf("%s\n",not_auth_str);
			break;
		case REASON_ASSOC_LEAVE:
			printf("%s\n",assoc_leave_str);
			break;
		case REASON_NO_AP_FOUND:
			printf("%s\n",no_ap_found_str);
			break;
		default:
			printf("%s%d\n",unknown_str,evt->event_info.disconnected.reason);
			break;
		}
		xSemaphoreGive(lock_sta);
	}
		break;
	case EVENT_STAMODE_GOT_IP:
		xSemaphoreGive(lock_sta);
		break;
	default:
		break;
	}
}
	